/*
 * Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.corba.se.impl.oa.poa;

import java.util.Collection;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;

import org.omg.CORBA.Policy;
import org.omg.CORBA.SystemException;

import org.omg.PortableServer.POA;
import org.omg.PortableServer.Servant;
import org.omg.PortableServer.POAManager;
import org.omg.PortableServer.AdapterActivator;
import org.omg.PortableServer.ServantManager;
import org.omg.PortableServer.ForwardRequest;
import org.omg.PortableServer.ThreadPolicy;
import org.omg.PortableServer.LifespanPolicy;
import org.omg.PortableServer.IdUniquenessPolicy;
import org.omg.PortableServer.IdAssignmentPolicy;
import org.omg.PortableServer.ImplicitActivationPolicy;
import org.omg.PortableServer.ServantRetentionPolicy;
import org.omg.PortableServer.RequestProcessingPolicy;
import org.omg.PortableServer.ThreadPolicyValue;
import org.omg.PortableServer.LifespanPolicyValue;
import org.omg.PortableServer.IdUniquenessPolicyValue;
import org.omg.PortableServer.IdAssignmentPolicyValue;
import org.omg.PortableServer.ImplicitActivationPolicyValue;
import org.omg.PortableServer.ServantRetentionPolicyValue;
import org.omg.PortableServer.RequestProcessingPolicyValue;
import org.omg.PortableServer.POAPackage.AdapterAlreadyExists;
import org.omg.PortableServer.POAPackage.AdapterNonExistent;
import org.omg.PortableServer.POAPackage.InvalidPolicy;
import org.omg.PortableServer.POAPackage.WrongPolicy;
import org.omg.PortableServer.POAPackage.WrongAdapter;
import org.omg.PortableServer.POAPackage.NoServant;
import org.omg.PortableServer.POAPackage.ServantAlreadyActive;
import org.omg.PortableServer.POAPackage.ObjectAlreadyActive;
import org.omg.PortableServer.POAPackage.ServantNotActive;
import org.omg.PortableServer.POAPackage.ObjectNotActive;

import org.omg.PortableInterceptor.ObjectReferenceFactory;
import org.omg.PortableInterceptor.ObjectReferenceTemplate;
import org.omg.PortableInterceptor.NON_EXISTENT;

import org.omg.IOP.TAG_INTERNET_IOP;

import com.sun.corba.se.spi.copyobject.CopierManager;
import com.sun.corba.se.spi.copyobject.ObjectCopier;
import com.sun.corba.se.spi.copyobject.ObjectCopierFactory;
import com.sun.corba.se.spi.oa.OADestroyed;
import com.sun.corba.se.spi.oa.OAInvocationInfo;
import com.sun.corba.se.spi.oa.ObjectAdapter;
import com.sun.corba.se.spi.oa.ObjectAdapterBase;
import com.sun.corba.se.spi.oa.ObjectAdapterFactory;
import com.sun.corba.se.spi.ior.ObjectKeyTemplate;
import com.sun.corba.se.spi.ior.ObjectId;
import com.sun.corba.se.spi.ior.ObjectAdapterId;
import com.sun.corba.se.spi.ior.IOR;
import com.sun.corba.se.spi.ior.IORFactories;
import com.sun.corba.se.spi.ior.IORTemplate;
import com.sun.corba.se.spi.ior.IORTemplateList;
import com.sun.corba.se.spi.ior.TaggedProfile;
import com.sun.corba.se.spi.ior.iiop.IIOPProfile;
import com.sun.corba.se.spi.ior.iiop.IIOPAddress;
import com.sun.corba.se.spi.ior.iiop.IIOPFactories;
import com.sun.corba.se.spi.orb.ORB;
import com.sun.corba.se.spi.protocol.ForwardException;
import com.sun.corba.se.spi.transport.SocketOrChannelAcceptor;

import com.sun.corba.se.impl.ior.POAObjectKeyTemplate;
import com.sun.corba.se.impl.ior.ObjectAdapterIdArray;
import com.sun.corba.se.impl.orbutil.ORBUtility;
import com.sun.corba.se.impl.orbutil.ORBConstants;
import com.sun.corba.se.impl.orbutil.concurrent.Sync;
import com.sun.corba.se.impl.orbutil.concurrent.SyncUtil;
import com.sun.corba.se.impl.orbutil.concurrent.ReentrantMutex;
import com.sun.corba.se.impl.orbutil.concurrent.CondVar;

/**
 * POAImpl is the implementation of the Portable Object Adapter. It
 * contains an implementation of the POA interfaces specified in
 * COBRA 2.3.1 chapter 11 (formal/99-10-07).  This implementation
 * is moving to comply with CORBA 3.0 due to the many clarifications
 * that have been made to the POA semantics since CORBA 2.3.1.
 * Specific comments have been added where 3.0 applies, but note that
 * we do not have the new 3.0 APIs yet.
 */
public class POAImpl extends ObjectAdapterBase implements POA {
    private boolean debug;

    /* POA creation takes place in 2 stages: first, the POAImpl constructor is
       called, then the initialize method is called.  This separation is
       needed because an AdapterActivator does not know the POAManager or
       the policies when
       the unknown_adapter method is invoked.  However, the POA must be created
       before the unknown_adapter method is invoked, so that the parent knows
       when concurrent attempts are made to create the same POA.
       Calling the POAImpl constructor results in a new POA in state STATE_START.
       Calling initialize( POAManager, Policies ) results in state STATE_RUN.
       Calling destroy results in STATE_DESTROY, which marks the beginning of
       POA destruction.
    */

    // Notes on concurrency.
    // The POA requires careful design for concurrency management to correctly
    // implement the specification and avoid deadlocks.  The order of acquiring
    // locks must respect the following locking hierarchy:
    //
    // 1. Lock POAs before POAManagers
    // 2. Lock a POA before locking its child POA
    //
    // Also note that there are 3 separate conditions on which threads may wait
    // in the POA, as defined by invokeCV, beingDestroyedCV, and
    // adapterActivatorCV.  This means that (for this reason as well as others)
    // we cannot simply use the standard Java synchronized primitive.
    // This implementation uses a modified version of Doug Lea's
    // util.concurrent (version 1.3.0) that supports reentrant
    // mutexes to handle the locking.  This will all be replaced by the new JSR
    // 166 concurrency primitives in J2SE 1.5 and later once the ORB moves to
    // J2SE 1.5.

    // POA state constants
    //
    // Note that ordering is important here: we must have the state defined in
    // this order so that ordered comparison is possible.
    // DO NOT CHANGE THE VALUES OF THE STATE CONSTANTS!!!  In particular, the
    // initialization related states must be lower than STATE_RUN.
    //
    // POA is created in STATE_START
    //
    // Valid state transitions:
    //
    // START to INIT                        after find_POA constructor call
    // START to RUN                         after initialize completes
    // INIT to INIT_DONE                    after initialize completes
    // INIT to DESTROYED                    after failed unknown_adapter
    // INIT_DONE to RUN                     after successful unknown_adapter
    // STATE_RUN to STATE_DESTROYING        after start of destruction
    // STATE_DESTROYING to STATE_DESTROYED  after destruction completes.

    private static final int STATE_START = 0; // constructor complete
    private static final int STATE_INIT = 1; // waiting for adapter activator
    private static final int STATE_INIT_DONE = 2; // adapter activator called create_POA
    private static final int STATE_RUN = 3; // initialized and running
    private static final int STATE_DESTROYING = 4; // being destroyed
    private static final int STATE_DESTROYED = 5; // destruction complete

    private String stateToString() {
        switch (state) {
            case STATE_START:
                return "START";
            case STATE_INIT:
                return "INIT";
            case STATE_INIT_DONE:
                return "INIT_DONE";
            case STATE_RUN:
                return "RUN";
            case STATE_DESTROYING:
                return "DESTROYING";
            case STATE_DESTROYED:
                return "DESTROYED";
            default:
                return "UNKNOWN(" + state + ")";
        }
    }

    // Current state of the POA
    private int state;

    // The POA request handler that performs all policy specific operations
    // Note that POAImpl handles all synchronization, so mediator is (mostly)
    // unsynchronized.
    private POAPolicyMediator mediator;

    // Representation of object adapter ID
    private int numLevels; // counts depth of tree.  Root = 1.
    private ObjectAdapterId poaId; // the actual object adapter ID for this POA
    private String name; // the name of this POA

    private POAManagerImpl manager; // This POA's POAManager
    private int uniquePOAId; // ID for this POA that is unique relative
                             // to the POAFactory, which has the same
                             // lifetime as the ORB.
    private POAImpl parent; // The POA that created this POA.
    private Map children; // Map from name to POA of POAs created by
                          // this POA.

    private AdapterActivator activator;
    private int invocationCount; // pending invocations on this POA.

    // Data used to control POA concurrency
    // XXX revisit for JSR 166

    // Master lock for all POA synchronization.  See lock and unlock.
    // package private for access by AOMEntry.
    Sync poaMutex;

    // Wait on this CV for AdapterActivator upcalls to complete
    private CondVar adapterActivatorCV;

    // Wait on this CV for all active invocations to complete
    private CondVar invokeCV;

    // Wait on this CV for the destroy method to complete doing its work
    private CondVar beingDestroyedCV;

    // thread local variable to store a boolean to detect deadlock in
    // POA.destroy().
    protected ThreadLocal isDestroying;

    // This includes the most important information for debugging
    // POA problems.
    public String toString() {
        return "POA[" + poaId.toString() + ", uniquePOAId=" + uniquePOAId + ", state=" + stateToString() + ", invocationCount=" + invocationCount + "]";
    }

    // package private for mediator implementations.
    boolean getDebug() {
        return debug;
    }

    // package private for access to servant to POA map
    static POAFactory getPOAFactory(ORB orb) {
        return (POAFactory) orb.getRequestDispatcherRegistry().getObjectAdapterFactory(ORBConstants.TRANSIENT_SCID);
    }

    // package private so that POAFactory can access it.
    static POAImpl makeRootPOA(ORB orb) {
        POAManagerImpl poaManager = new POAManagerImpl(getPOAFactory(orb), orb.getPIHandler());

        POAImpl result = new POAImpl(ORBConstants.ROOT_POA_NAME, null, orb, STATE_START);
        result.initialize(poaManager, Policies.rootPOAPolicies);

        return result;
    }

    // package private so that POAPolicyMediatorBase can access it.
    int getPOAId() {
        return uniquePOAId;
    }

    // package private so that POAPolicyMediator can access it.
    void lock() {
        SyncUtil.acquire(poaMutex);

        if (debug) {
            ORBUtility.dprint(this, "LOCKED poa " + this);
        }
    }

    // package private so that POAPolicyMediator can access it.
    void unlock() {
        if (debug) {
            ORBUtility.dprint(this, "UNLOCKED poa " + this);
        }

        poaMutex.release();
    }

    // package private so that DelegateImpl can access it.
    Policies getPolicies() {
        return mediator.getPolicies();
    }

    // Note that the parent POA must be locked when this constructor is called.
    private POAImpl(String name, POAImpl parent, ORB orb, int initialState) {
        super(orb);

        debug = orb.poaDebugFlag;

        if (debug) {
            ORBUtility.dprint(this, "Creating POA with name=" + name + " parent=" + parent);
        }

        this.state = initialState;
        this.name = name;
        this.parent = parent;
        children = new HashMap();
        activator = null;

        // This was done in initialize, but I moved it here
        // to get better searchability when tracing.
        uniquePOAId = getPOAFactory(orb).newPOAId();

        if (parent == null) {
            // This is the root POA, which counts as 1 level
            numLevels = 1;
        } else {
            // My level is one more than that of my parent
            numLevels = parent.numLevels + 1;

            parent.children.put(name, this);
        }

        // Get an array of all of the POA names in order to
        // create the poaid.
        String[] names = new String[numLevels];
        POAImpl poaImpl = this;
        int ctr = numLevels - 1;
        while (poaImpl != null) {
            names[ctr--] = poaImpl.name;
            poaImpl = poaImpl.parent;
        }

        poaId = new ObjectAdapterIdArray(names);

        invocationCount = 0;

        poaMutex = new ReentrantMutex(orb.poaConcurrencyDebugFlag);

        adapterActivatorCV = new CondVar(poaMutex, orb.poaConcurrencyDebugFlag);
        invokeCV = new CondVar(poaMutex, orb.poaConcurrencyDebugFlag);
        beingDestroyedCV = new CondVar(poaMutex, orb.poaConcurrencyDebugFlag);

        isDestroying = new ThreadLocal() {
            protected java.lang.Object initialValue() {
                return Boolean.FALSE;
            }
        };
    }

    // The POA lock must be held when this method is called.
    private void initialize(POAManagerImpl manager, Policies policies) {
        if (debug) {
            ORBUtility.dprint(this, "Initializing poa " + this + " with POAManager=" + manager + " policies=" + policies);
        }

        this.manager = manager;
        manager.addPOA(this);

        mediator = POAPolicyMediatorFactory.create(policies, this);

        // Construct the object key template
        int serverid = mediator.getServerId();
        int scid = mediator.getScid();
        String orbId = getORB().getORBData().getORBId();

        ObjectKeyTemplate oktemp = new POAObjectKeyTemplate(getORB(), scid, serverid, orbId, poaId);

        if (debug) {
            ORBUtility.dprint(this, "Initializing poa: oktemp=" + oktemp);
        }

        // Note that parent == null iff this is the root POA.
        // This was used to avoid executing interceptors on the RootPOA.
        // That is no longer necessary.
        boolean objectAdapterCreated = true; // parent != null ;

        // XXX extract codebase from policies and pass into initializeTemplate
        // after the codebase policy change is finalized.
        initializeTemplate(oktemp, objectAdapterCreated, policies, null, // codebase
        null, // manager id
        oktemp.getObjectAdapterId());

        if (state == STATE_START)
            state = STATE_RUN;
        else if (state == STATE_INIT)
            state = STATE_INIT_DONE;
        else
            throw lifecycleWrapper().illegalPoaStateTrans();
    }

    // The poaMutex must be held when this method is called
    private boolean waitUntilRunning() {
        if (debug) {
            ORBUtility.dprint(this, "Calling waitUntilRunning on poa " + this);
        }

        while (state < STATE_RUN) {
            try {
                adapterActivatorCV.await();
            } catch (InterruptedException exc) {
                // NO-OP
            }
        }

        if (debug) {
            ORBUtility.dprint(this, "Exiting waitUntilRunning on poa " + this);
        }

        // Note that a POA could be destroyed while in STATE_INIT due to a
        // failure in the AdapterActivator upcall.
        return (state == STATE_RUN);
    }

    // This method checks that the AdapterActivator finished the
    // initialization of a POA activated in find_POA.  This is
    // determined by checking the state of the POA.  If the state is
    // STATE_INIT, the AdapterActivator did not complete the
    // inialization.  In this case, we destroy the POA that was
    // partially created and return false.  Otherwise, we return true.
    // In any case, we must wake up all threads waiting for the adapter
    // activator, either to continue their invocations, or to return
    // errors to their client.
    //
    // The poaMutex must NOT be held when this method is called.
    private boolean destroyIfNotInitDone() {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling destroyIfNotInitDone on poa " + this);
            }

            boolean success = (state == STATE_INIT_DONE);

            if (success)
                state = STATE_RUN;
            else {
                // Don't just use destroy, because the check for
                // deadlock is too general, and can prevent this from
                // functioning properly.
                DestroyThread destroyer = new DestroyThread(false, debug);
                destroyer.doIt(this, true);
            }

            return success;
        } finally {
            adapterActivatorCV.broadcast();

            if (debug) {
                ORBUtility.dprint(this, "Exiting destroyIfNotInitDone on poa " + this);
            }

            unlock();
        }
    }

    private byte[] internalReferenceToId(org.omg.CORBA.Object reference) throws WrongAdapter {
        IOR ior = ORBUtility.getIOR(reference);
        IORTemplateList thisTemplate = ior.getIORTemplates();

        ObjectReferenceFactory orf = getCurrentFactory();
        IORTemplateList poaTemplate = IORFactories.getIORTemplateList(orf);

        if (!poaTemplate.isEquivalent(thisTemplate))
            throw new WrongAdapter();

        // Extract the ObjectId from the first TaggedProfile in the IOR.
        // If ior was created in this POA, the same ID was used for
        // every profile through the profile templates in the currentFactory,
        // so we will get the same result from any profile.
        Iterator iter = ior.iterator();
        if (!iter.hasNext())
            throw iorWrapper().noProfilesInIor();
        TaggedProfile prof = (TaggedProfile) (iter.next());
        ObjectId oid = prof.getObjectId();

        return oid.getId();
    }

    // Converted from anonymous class to local class
    // so that we can call performDestroy() directly.
    static class DestroyThread extends Thread {
        private boolean wait;
        private boolean etherealize;
        private boolean debug;
        private POAImpl thePoa;

        public DestroyThread(boolean etherealize, boolean debug) {
            this.etherealize = etherealize;
            this.debug = debug;
        }

        public void doIt(POAImpl thePoa, boolean wait) {
            if (debug) {
                ORBUtility.dprint(this, "Calling DestroyThread.doIt(thePOA=" + thePoa + " wait=" + wait + " etherealize=" + etherealize);
            }

            this.thePoa = thePoa;
            this.wait = wait;

            if (wait) {
                run();
            } else {
                // Catch exceptions since setDaemon can cause a
                // security exception to be thrown under netscape
                // in the Applet mode
                try {
                    setDaemon(true);
                } catch (Exception e) {
                }
                start();
            }
        }

        public void run() {
            Set destroyedPOATemplates = new HashSet();

            performDestroy(thePoa, destroyedPOATemplates);

            Iterator iter = destroyedPOATemplates.iterator();
            ObjectReferenceTemplate[] orts = new ObjectReferenceTemplate[destroyedPOATemplates.size()];
            int index = 0;
            while (iter.hasNext())
                orts[index++] = (ObjectReferenceTemplate) iter.next();

            thePoa.getORB().getPIHandler().adapterStateChanged(orts, NON_EXISTENT.value);
        }

        // Returns true if destruction must be completed, false
        // if not, which means that another thread is already
        // destroying poa.
        private boolean prepareForDestruction(POAImpl poa, Set destroyedPOATemplates) {
            POAImpl[] childPoas = null;

            // Note that we do not synchronize on this, since this is
            // the PerformDestroy instance, not the POA.
            try {
                poa.lock();

                if (debug) {
                    ORBUtility.dprint(this, "Calling performDestroy on poa " + poa);
                }

                if (poa.state <= STATE_RUN) {
                    poa.state = STATE_DESTROYING;
                } else {
                    // destroy may be called multiple times, and each call
                    // is allowed to proceed with its own setting of the wait
                    // flag, but the etherealize value is used from the first
                    // call to destroy.  Also all children should be destroyed
                    // before the parent POA.  If the poa is already destroyed,
                    // we can just return.  If the poa has started destruction,
                    // but not completed, and wait is true, we need to wait
                    // until destruction is complete, then just return.
                    if (wait)
                        while (poa.state != STATE_DESTROYED) {
                            try {
                                poa.beingDestroyedCV.await();
                            } catch (InterruptedException exc) {
                                // NO-OP
                            }
                        }

                    return false;
                }

                poa.isDestroying.set(Boolean.TRUE);

                // Make a copy since we can't hold the lock while destroying
                // the children, and an iterator is not deletion-safe.
                childPoas = (POAImpl[]) poa.children.values().toArray(new POAImpl[0]);
            } finally {
                poa.unlock();
            }

            // We are not holding the POA mutex here to avoid holding it
            // while destroying the POA's children, since this may involve
            // upcalls to etherealize methods.

            for (int ctr = 0; ctr < childPoas.length; ctr++) {
                performDestroy(childPoas[ctr], destroyedPOATemplates);
            }

            return true;
        }

        public void performDestroy(POAImpl poa, Set destroyedPOATemplates) {
            if (!prepareForDestruction(poa, destroyedPOATemplates))
                return;

            // NOTE: If we are here, poa is in STATE_DESTROYING state. All
            // other state checks are taken care of in prepareForDestruction.
            // No other threads may either be starting new invocations
            // by calling enter or starting to destroy poa.  There may
            // still be pending invocations.

            POAImpl parent = poa.parent;
            boolean isRoot = parent == null;

            try {
                // Note that we must lock the parent before the child.
                // The parent lock is required (if poa is not the root)
                // to safely remove poa from parent's children Map.
                if (!isRoot)
                    parent.lock();

                try {
                    poa.lock();

                    completeDestruction(poa, parent, destroyedPOATemplates);
                } finally {
                    poa.unlock();

                    if (isRoot)
                        // We have just destroyed the root POA, so we need to
                        // make sure that the next call to
                        // resolve_initial_reference( "RootPOA" )
                        // will recreate a valid root POA.
                        poa.manager.getFactory().registerRootPOA();
                }
            } finally {
                if (!isRoot) {
                    parent.unlock();
                    poa.parent = null;
                }
            }
        }

        private void completeDestruction(POAImpl poa, POAImpl parent, Set destroyedPOATemplates) {
            if (debug) {
                ORBUtility.dprint(this, "Calling completeDestruction on poa " + poa);
            }

            try {
                while (poa.invocationCount != 0) {
                    try {
                        poa.invokeCV.await();
                    } catch (InterruptedException ex) {
                        // NO-OP
                    }
                }

                if (poa.mediator != null) {
                    if (etherealize)
                        poa.mediator.etherealizeAll();

                    poa.mediator.clearAOM();
                }

                if (poa.manager != null)
                    poa.manager.removePOA(poa);

                if (parent != null)
                    parent.children.remove(poa.name);

                destroyedPOATemplates.add(poa.getAdapterTemplate());
            } catch (Throwable thr) {
                if (thr instanceof ThreadDeath)
                    throw (ThreadDeath) thr;

                poa.lifecycleWrapper().unexpectedException(thr, poa.toString());
            } finally {
                poa.state = STATE_DESTROYED;
                poa.beingDestroyedCV.broadcast();
                poa.isDestroying.set(Boolean.FALSE);

                if (debug) {
                    ORBUtility.dprint(this, "Exiting completeDestruction on poa " + poa);
                }
            }
        }
    }

    void etherealizeAll() {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling etheralizeAll on poa " + this);
            }

            mediator.etherealizeAll();
        } finally {
            if (debug) {
                ORBUtility.dprint(this, "Exiting etheralizeAll on poa " + this);
            }

            unlock();
        }
    }

    //*******************************************************************
    // Public POA API
    //*******************************************************************

    /**
     * <code>create_POA</code>
     * <b>Section 3.3.8.2</b>
     */
    public POA create_POA(String name, POAManager theManager, Policy[] policies) throws AdapterAlreadyExists, InvalidPolicy {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling create_POA(name=" + name + " theManager=" + theManager + " policies=" + policies + ") on poa " + this);
            }

            // We cannot create children of a POA that is (being) destroyed.
            // This has been added to the CORBA 3.0 spec.
            if (state > STATE_RUN)
                throw omgLifecycleWrapper().createPoaDestroy();

            POAImpl poa = (POAImpl) (children.get(name));

            if (poa == null) {
                poa = new POAImpl(name, this, getORB(), STATE_START);
            }

            try {
                poa.lock();

                if (debug) {
                    ORBUtility.dprint(this, "Calling create_POA: new poa is " + poa);
                }

                if ((poa.state != STATE_START) && (poa.state != STATE_INIT))
                    throw new AdapterAlreadyExists();

                POAManagerImpl newManager = (POAManagerImpl) theManager;
                if (newManager == null)
                    newManager = new POAManagerImpl(manager.getFactory(), manager.getPIHandler());

                int defaultCopierId = getORB().getCopierManager().getDefaultId();
                Policies POAPolicies = new Policies(policies, defaultCopierId);

                poa.initialize(newManager, POAPolicies);

                return poa;
            } finally {
                poa.unlock();
            }
        } finally {
            unlock();
        }
    }

    /**
     * <code>find_POA</code>
     * <b>Section 3.3.8.3</b>
     */
    public POA find_POA(String name, boolean activate) throws AdapterNonExistent {
        POAImpl found = null;
        AdapterActivator act = null;

        lock();

        if (debug) {
            ORBUtility.dprint(this, "Calling find_POA(name=" + name + " activate=" + activate + ") on poa " + this);
        }

        found = (POAImpl) children.get(name);

        if (found != null) {
            if (debug) {
                ORBUtility.dprint(this, "Calling find_POA: found poa " + found);
            }

            try {
                found.lock();

                // Do not hold the parent POA lock while
                // waiting for child to complete initialization.
                unlock();

                // Make sure that the child has completed its initialization,
                // if it was created by an AdapterActivator, otherwise throw
                // a standard TRANSIENT exception with minor code 4 (see
                // CORBA 3.0 11.3.9.3, in reference to unknown_adapter)
                if (!found.waitUntilRunning())
                    throw omgLifecycleWrapper().poaDestroyed();

                // Note that found may be in state DESTROYING or DESTROYED at
                // this point.  That's OK, since destruction could start at
                // any time.
            } finally {
                found.unlock();
            }
        } else {
            try {
                if (debug) {
                    ORBUtility.dprint(this, "Calling find_POA: no poa found");
                }

                if (activate && (activator != null)) {
                    // Create a child, but don't initialize it.  The newly
                    // created POA will be in state STATE_START, which will
                    // cause other calls to find_POA that are creating the same
                    // POA to block on the waitUntilRunning call above.
                    // Initialization must be completed by a call to create_POA
                    // inside the unknown_adapter upcall.  Note that
                    // this.poaMutex must be held here so that this.children
                    // can be safely updated.  The state is set to STATE_INIT
                    // so that initialize can make the correct state transition
                    // when create_POA is called inside the AdapterActivator.
                    // This avoids activating the new POA too soon
                    // by transitioning to STATE_RUN after unknown_adapter
                    // returns.
                    found = new POAImpl(name, this, getORB(), STATE_INIT);

                    if (debug) {
                        ORBUtility.dprint(this, "Calling find_POA: created poa " + found);
                    }

                    act = activator;
                } else {
                    throw new AdapterNonExistent();
                }
            } finally {
                unlock();
            }
        }

        // assert (found != null)
        // assert not holding this.poaMutex OR found.poaMutex

        // We must not hold either this.poaMutex or found.poaMutex here while
        // waiting for intialization of found to complete to prevent possible
        // deadlocks.

        if (act != null) {
            boolean status = false;
            boolean adapterResult = false;

            if (debug) {
                ORBUtility.dprint(this, "Calling find_POA: calling AdapterActivator");
            }

            try {
                // Prevent more than one thread at a time from executing in act
                // in case act is shared between multiple POAs.
                synchronized (act) {
                    status = act.unknown_adapter(this, name);
                }
            } catch (SystemException exc) {
                throw omgLifecycleWrapper().adapterActivatorException(exc, name, poaId.toString());
            } catch (Throwable thr) {
                // ignore most non-system exceptions, but log them for
                // diagnostic purposes.
                lifecycleWrapper().unexpectedException(thr, this.toString());

                if (thr instanceof ThreadDeath)
                    throw (ThreadDeath) thr;
            } finally {
                // At this point, we have completed adapter activation.
                // Whether this was successful or not, we must call
                // destroyIfNotInitDone so that calls to enter() and create_POA()
                // that are waiting can execute again.  Failing to do this
                // will cause the system to hang in complex tests.
                adapterResult = found.destroyIfNotInitDone();
            }

            if (status) {
                if (!adapterResult)
                    throw omgLifecycleWrapper().adapterActivatorException(name, poaId.toString());
            } else {
                if (debug) {
                    ORBUtility.dprint(this, "Calling find_POA: AdapterActivator returned false");
                }

                // OMG Issue 3740 is resolved to throw AdapterNonExistent if
                // unknown_adapter() returns false.
                throw new AdapterNonExistent();
            }
        }

        return found;
    }

    /**
     * <code>destroy</code>
     * <b>Section 3.3.8.4</b>
     */
    public void destroy(boolean etherealize, boolean wait_for_completion) {
        // This is to avoid deadlock
        if (wait_for_completion && getORB().isDuringDispatch()) {
            throw lifecycleWrapper().destroyDeadlock();
        }

        DestroyThread destroyer = new DestroyThread(etherealize, debug);
        destroyer.doIt(this, wait_for_completion);
    }

    /**
     * <code>create_thread_policy</code>
     * <b>Section 3.3.8.5</b>
     */
    public ThreadPolicy create_thread_policy(ThreadPolicyValue value) {
        return new ThreadPolicyImpl(value);
    }

    /**
     * <code>create_lifespan_policy</code>
     * <b>Section 3.3.8.5</b>
     */
    public LifespanPolicy create_lifespan_policy(LifespanPolicyValue value) {
        return new LifespanPolicyImpl(value);
    }

    /**
     * <code>create_id_uniqueness_policy</code>
     * <b>Section 3.3.8.5</b>
     */
    public IdUniquenessPolicy create_id_uniqueness_policy(IdUniquenessPolicyValue value) {
        return new IdUniquenessPolicyImpl(value);
    }

    /**
     * <code>create_id_assignment_policy</code>
     * <b>Section 3.3.8.5</b>
     */
    public IdAssignmentPolicy create_id_assignment_policy(IdAssignmentPolicyValue value) {
        return new IdAssignmentPolicyImpl(value);
    }

    /**
     * <code>create_implicit_activation_policy</code>
     * <b>Section 3.3.8.5</b>
     */
    public ImplicitActivationPolicy create_implicit_activation_policy(ImplicitActivationPolicyValue value) {
        return new ImplicitActivationPolicyImpl(value);
    }

    /**
     * <code>create_servant_retention_policy</code>
     * <b>Section 3.3.8.5</b>
     */
    public ServantRetentionPolicy create_servant_retention_policy(ServantRetentionPolicyValue value) {
        return new ServantRetentionPolicyImpl(value);
    }

    /**
     * <code>create_request_processing_policy</code>
     * <b>Section 3.3.8.5</b>
     */
    public RequestProcessingPolicy create_request_processing_policy(RequestProcessingPolicyValue value) {
        return new RequestProcessingPolicyImpl(value);
    }

    /**
     * <code>the_name</code>
     * <b>Section 3.3.8.6</b>
     */
    public String the_name() {
        try {
            lock();

            return name;
        } finally {
            unlock();
        }
    }

    /**
     * <code>the_parent</code>
     * <b>Section 3.3.8.7</b>
     */
    public POA the_parent() {
        try {
            lock();

            return parent;
        } finally {
            unlock();
        }
    }

    /**
     * <code>the_children</code>
     */
    public org.omg.PortableServer.POA[] the_children() {
        try {
            lock();

            Collection coll = children.values();
            int size = coll.size();
            POA[] result = new POA[size];
            int index = 0;
            Iterator iter = coll.iterator();
            while (iter.hasNext()) {
                POA poa = (POA) (iter.next());
                result[index++] = poa;
            }

            return result;
        } finally {
            unlock();
        }
    }

    /**
     * <code>the_POAManager</code>
     * <b>Section 3.3.8.8</b>
     */
    public POAManager the_POAManager() {
        try {
            lock();

            return manager;
        } finally {
            unlock();
        }
    }

    /**
     * <code>the_activator</code>
     * <b>Section 3.3.8.9</b>
     */
    public AdapterActivator the_activator() {
        try {
            lock();

            return activator;
        } finally {
            unlock();
        }
    }

    /**
     * <code>the_activator</code>
     * <b>Section 3.3.8.9</b>
     */
    public void the_activator(AdapterActivator activator) {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling the_activator on poa " + this + " activator=" + activator);
            }

            this.activator = activator;
        } finally {
            unlock();
        }
    }

    /**
     * <code>get_servant_manager</code>
     * <b>Section 3.3.8.10</b>
     */
    public ServantManager get_servant_manager() throws WrongPolicy {
        try {
            lock();

            return mediator.getServantManager();
        } finally {
            unlock();
        }
    }

    /**
     * <code>set_servant_manager</code>
     * <b>Section 3.3.8.10</b>
     */
    public void set_servant_manager(ServantManager servantManager) throws WrongPolicy {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling set_servant_manager on poa " + this + " servantManager=" + servantManager);
            }

            mediator.setServantManager(servantManager);
        } finally {
            unlock();
        }
    }

    /**
     * <code>get_servant</code>
     * <b>Section 3.3.8.12</b>
     */
    public Servant get_servant() throws NoServant, WrongPolicy {
        try {
            lock();

            return mediator.getDefaultServant();
        } finally {
            unlock();
        }
    }

    /**
     * <code>set_servant</code>
     * <b>Section 3.3.8.13</b>
     */
    public void set_servant(Servant defaultServant) throws WrongPolicy {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling set_servant on poa " + this + " defaultServant=" + defaultServant);
            }

            mediator.setDefaultServant(defaultServant);
        } finally {
            unlock();
        }
    }

    /**
     * <code>activate_object</code>
     * <b>Section 3.3.8.14</b>
     */
    public byte[] activate_object(Servant servant) throws ServantAlreadyActive, WrongPolicy {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling activate_object on poa " + this + " (servant=" + servant + ")");
            }

            // Allocate a new system-generated object-id.
            // This will throw WrongPolicy if not SYSTEM_ID
            // policy.
            byte[] id = mediator.newSystemId();

            try {
                mediator.activateObject(id, servant);
            } catch (ObjectAlreadyActive oaa) {
                // This exception can not occur in this case,
                // since id is always brand new.
                //
            }

            return id;
        } finally {
            if (debug) {
                ORBUtility.dprint(this, "Exiting activate_object on poa " + this);
            }

            unlock();
        }
    }

    /**
     * <code>activate_object_with_id</code>
     * <b>Section 3.3.8.15</b>
     */
    public void activate_object_with_id(byte[] id, Servant servant) throws ObjectAlreadyActive, ServantAlreadyActive, WrongPolicy {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling activate_object_with_id on poa " + this + " (servant=" + servant + " id=" + id + ")");
            }

            // Clone the id to avoid possible errors due to aliasing
            // (e.g. the client passes the id in and then changes it later).
            byte[] idClone = (byte[]) (id.clone());

            mediator.activateObject(idClone, servant);
        } finally {
            if (debug) {
                ORBUtility.dprint(this, "Exiting activate_object_with_id on poa " + this);
            }

            unlock();
        }
    }

    /**
     * <code>deactivate_object</code>
     * <b>3.3.8.16</b>
     */
    public void deactivate_object(byte[] id) throws ObjectNotActive, WrongPolicy {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling deactivate_object on poa " + this + " (id=" + id + ")");
            }

            mediator.deactivateObject(id);
        } finally {
            if (debug) {
                ORBUtility.dprint(this, "Exiting deactivate_object on poa " + this);
            }

            unlock();
        }
    }

    /**
     * <code>create_reference</code>
     * <b>3.3.8.17</b>
     */
    public org.omg.CORBA.Object create_reference(String repId) throws WrongPolicy {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling create_reference(repId=" + repId + ") on poa " + this);
            }

            return makeObject(repId, mediator.newSystemId());
        } finally {
            unlock();
        }
    }

    /**
     * <code>create_reference_with_id</code>
     * <b>3.3.8.18</b>
     */
    public org.omg.CORBA.Object create_reference_with_id(byte[] oid, String repId) {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling create_reference_with_id(oid=" + oid + " repId=" + repId + ") on poa " + this);
            }

            // Clone the id to avoid possible errors due to aliasing
            // (e.g. the client passes the id in and then changes it later).
            byte[] idClone = (byte[]) (oid.clone());

            return makeObject(repId, idClone);
        } finally {
            unlock();
        }
    }

    /**
     * <code>servant_to_id</code>
     * <b>3.3.8.19</b>
     */
    public byte[] servant_to_id(Servant servant) throws ServantNotActive, WrongPolicy {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling servant_to_id(servant=" + servant + ") on poa " + this);
            }

            return mediator.servantToId(servant);
        } finally {
            unlock();
        }
    }

    /**
     * <code>servant_to_reference</code>
     * <b>3.3.8.20</b>
     */
    public org.omg.CORBA.Object servant_to_reference(Servant servant) throws ServantNotActive, WrongPolicy {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling servant_to_reference(servant=" + servant + ") on poa " + this);
            }

            byte[] oid = mediator.servantToId(servant);
            String repId = servant._all_interfaces(this, oid)[0];
            return create_reference_with_id(oid, repId);
        } finally {
            unlock();
        }
    }

    /**
     * <code>reference_to_servant</code>
     * <b>3.3.8.21</b>
     */
    public Servant reference_to_servant(org.omg.CORBA.Object reference) throws ObjectNotActive, WrongPolicy, WrongAdapter {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling reference_to_servant(reference=" + reference + ") on poa " + this);
            }

            if (state >= STATE_DESTROYING) {
                throw lifecycleWrapper().adapterDestroyed();
            }

            // reference_to_id should throw WrongAdapter
            // if the objref was not created by this POA
            byte[] id = internalReferenceToId(reference);

            return mediator.idToServant(id);
        } finally {
            unlock();
        }
    }

    /**
     * <code>reference_to_id</code>
     * <b>3.3.8.22</b>
     */
    public byte[] reference_to_id(org.omg.CORBA.Object reference) throws WrongAdapter, WrongPolicy {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling reference_to_id(reference=" + reference + ") on poa " + this);
            }

            if (state >= STATE_DESTROYING) {
                throw lifecycleWrapper().adapterDestroyed();
            }

            return internalReferenceToId(reference);
        } finally {
            unlock();
        }
    }

    /**
     * <code>id_to_servant</code>
     * <b>3.3.8.23</b>
     */
    public Servant id_to_servant(byte[] id) throws ObjectNotActive, WrongPolicy {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling id_to_servant(id=" + id + ") on poa " + this);
            }

            if (state >= STATE_DESTROYING) {
                throw lifecycleWrapper().adapterDestroyed();
            }
            return mediator.idToServant(id);
        } finally {
            unlock();
        }
    }

    /**
     * <code>id_to_reference</code>
     * <b>3.3.8.24</b>
     */
    public org.omg.CORBA.Object id_to_reference(byte[] id) throws ObjectNotActive, WrongPolicy

    {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling id_to_reference(id=" + id + ") on poa " + this);
            }

            if (state >= STATE_DESTROYING) {
                throw lifecycleWrapper().adapterDestroyed();
            }

            Servant s = mediator.idToServant(id);
            String repId = s._all_interfaces(this, id)[0];
            return makeObject(repId, id);
        } finally {
            unlock();
        }
    }

    /**
     * <code>id</code>
     * <b>11.3.8.26 in ptc/00-08-06</b>
     */
    public byte[] id() {
        try {
            lock();

            return getAdapterId();
        } finally {
            unlock();
        }
    }

    //***************************************************************
    //Implementation of ObjectAdapter interface
    //***************************************************************

    public Policy getEffectivePolicy(int type) {
        return mediator.getPolicies().get_effective_policy(type);
    }

    public int getManagerId() {
        return manager.getManagerId();
    }

    public short getState() {
        return manager.getORTState();
    }

    public String[] getInterfaces(java.lang.Object servant, byte[] objectId) {
        Servant serv = (Servant) servant;
        return serv._all_interfaces(this, objectId);
    }

    protected ObjectCopierFactory getObjectCopierFactory() {
        int copierId = mediator.getPolicies().getCopierId();
        CopierManager cm = getORB().getCopierManager();
        return cm.getObjectCopierFactory(copierId);
    }

    public void enter() throws OADestroyed {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling enter on poa " + this);
            }

            // Avoid deadlock if this is the thread that is processing the
            // POA.destroy because this is the only thread that can notify
            // waiters on beingDestroyedCV.  This can happen if an
            // etherealize upcall invokes a method on a colocated object
            // served by this POA.
            while ((state == STATE_DESTROYING) && (isDestroying.get() == Boolean.FALSE)) {
                try {
                    beingDestroyedCV.await();
                } catch (InterruptedException ex) {
                    // NO-OP
                }
            }

            if (!waitUntilRunning())
                throw new OADestroyed();

            invocationCount++;
        } finally {
            if (debug) {
                ORBUtility.dprint(this, "Exiting enter on poa " + this);
            }

            unlock();
        }

        manager.enter();
    }

    public void exit() {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling exit on poa " + this);
            }

            invocationCount--;

            if ((invocationCount == 0) && (state == STATE_DESTROYING)) {
                invokeCV.broadcast();
            }
        } finally {
            if (debug) {
                ORBUtility.dprint(this, "Exiting exit on poa " + this);
            }

            unlock();
        }

        manager.exit();
    }

    public void getInvocationServant(OAInvocationInfo info) {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling getInvocationServant on poa " + this);
            }

            java.lang.Object servant = null;

            try {
                servant = mediator.getInvocationServant(info.id(), info.getOperation());
            } catch (ForwardRequest freq) {
                throw new ForwardException(getORB(), freq.forward_reference);
            }

            info.setServant(servant);
        } finally {
            if (debug) {
                ORBUtility.dprint(this, "Exiting getInvocationServant on poa " + this);
            }

            unlock();
        }
    }

    public org.omg.CORBA.Object getLocalServant(byte[] objectId) {
        return null;
    }

    /** Called from the subcontract to let this POA cleanup after an
     *  invocation. Note: If getServant was called, then returnServant
     *  MUST be called, even in the case of exceptions.  This may be
     *  called multiple times for a single request.
     */
    public void returnServant() {
        try {
            lock();

            if (debug) {
                ORBUtility.dprint(this, "Calling returnServant on poa " + this);
            }

            mediator.returnServant();
        } catch (Throwable thr) {
            if (debug) {
                ORBUtility.dprint(this, "Exception " + thr + " in returnServant on poa " + this);
            }

            if (thr instanceof Error)
                throw (Error) thr;
            else if (thr instanceof RuntimeException)
                throw (RuntimeException) thr;

        } finally {
            if (debug) {
                ORBUtility.dprint(this, "Exiting returnServant on poa " + this);
            }

            unlock();
        }
    }
}
